/*
 * This file is part of b.AMP.
 *
 * b.AMP is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * b.AMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with b.AMP.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "dynamic_lib.hpp"
#include <bamp/exception.hpp>
#include <boost/filesystem.hpp>
#include <dlfcn.h>

struct bamp::DynamicLib::Implementation
{
    void* handle; // Libdl handle
};

bamp::DynamicLib::DynamicLib(const boost::filesystem::path& path)
    : pimpl(new Implementation)
{
    // Load the dynamic library specified by the path. If it fails, it
    // is very likely that the specified path was not found.
    const std::string file = path.string() + ".so";
    pimpl->handle = dlopen(file.c_str(), RTLD_NOW);
    BAMP_ASSERT_THROW(pimpl->handle != NULL, NOT_FOUND);
}

bamp::DynamicLib::~DynamicLib()
{
    // Decrement libdl's reference counter and close if it reaches zero.
    dlclose(pimpl->handle);
}

void* bamp::DynamicLib::_resolve(const std::string& name)
{
    // Resolve the symbol. If it is not found, dlsym() returns NULL.
    void* sym = dlsym(pimpl->handle, name.c_str());
    BAMP_ASSERT_THROW(sym != NULL, NOT_FOUND);
    return sym;
}
